package jsoniterx

import (
	"gitee.com/youbeiwuhuan/taotao-tools4go/base-tools/tagx"
	"gitee.com/youbeiwuhuan/taotao-tools4go/base-tools/utils/reflectx"
	jsoniter "github.com/json-iterator/go"
	"reflect"
	"strconv"
	"strings"
	"unsafe"
)

// 字段打码的实现
type MaskEncoder struct {
	binding  *jsoniter.Binding
	tagValue string
}

func (en *MaskEncoder) IsEmpty(ptr unsafe.Pointer) bool {
	return reflectx.IsPointerZero(ptr, en.binding.Field.Type().Type1())
}
func (en *MaskEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
	if "" == strings.TrimSpace(en.tagValue) {
		return
	}

	maskChar := getMaskChar(en.tagValue)
	start := getStart(en.tagValue)
	end := getEnd(en.tagValue)

	var maskStr string
	type2 := en.binding.Field.Type()

	switch type2.Kind() {
	case reflect.Array, reflect.Struct, reflect.Interface, reflect.Ptr, reflect.Uintptr, reflect.Bool, reflect.Complex64, reflect.Complex128:
		// 这几种类型不处理
		break

	case reflect.String:
		v := *(*string)(ptr)
		maskStr = v
		break

		break
	case reflect.Int:
		v := *(*int)(ptr)
		maskStr = strconv.Itoa(v)
		break
	case reflect.Int8:
		v := *(*int8)(ptr)
		maskStr = strconv.FormatInt(int64(v), 10)
		break
	case reflect.Int16:
		v := *(*int16)(ptr)
		maskStr = strconv.FormatInt(int64(v), 10)
		break
	case reflect.Int32: // int32 和 rune
		v := *(*int32)(ptr)
		maskStr = strconv.FormatInt(int64(v), 10)
		break
	case reflect.Int64:
		v := *(*int64)(ptr)
		maskStr = strconv.FormatInt(v, 10)
		break

	case reflect.Uint:
		v := *(*uint)(ptr)
		maskStr = strconv.FormatUint(uint64(v), 10)
		break
	case reflect.Uint8: // uint8和byte
		v := *(*uint8)(ptr)
		maskStr = strconv.FormatUint(uint64(v), 10)
		break
	case reflect.Uint16:
		v := *(*uint16)(ptr)
		maskStr = strconv.FormatUint(uint64(v), 10)
		break
	case reflect.Uint32:
		v := *(*uint32)(ptr)
		maskStr = strconv.FormatUint(uint64(v), 10)
		break
	case reflect.Uint64:
		v := *(*uint64)(ptr)
		maskStr = strconv.FormatUint(v, 10)
		break
	case reflect.Float32:
		v := *(*float32)(ptr)
		maskStr = strconv.FormatFloat(float64(v), 'f', -1, 64)
		break
	case reflect.Float64:
		v := *(*float64)(ptr)
		maskStr = strconv.FormatFloat(v, 'f', -1, 64)
		break
	}

	stream.WriteString(MaskStr(maskStr, maskChar, start, end))

}

func getEnd(tagValue string) int {

	s := getStr(tagValue, tagx.MaskEnd)
	i, err := strconv.Atoi(s)
	if err != nil {
		panic("mask tag format error")
	}

	return i

}

func getStart(tagValue string) int {
	s := getStr(tagValue, tagx.MaskStart)
	i, err := strconv.Atoi(s)
	if err != nil {
		panic("mask tag format error")
	}

	return i
}

func getMaskChar(tagValue string) rune {
	s := getStr(tagValue, tagx.MaskChar)
	if len(s) == 0 {
		panic("mask tag format error")
	}

	return []rune(s)[0]
}

func getStr(tagValue string, tname string) string {
	sArr := strings.Split(tagValue, ",")

	for _, s := range sArr {
		vArr := strings.Split(s, "=")
		if len(vArr) != 2 {
			panic("mask tag format error")
		}

		if vArr[0] == tname {
			return vArr[1]
		}

	}

	return ""
}

func MaskStr(s string, maskChar rune, start int, end int) string {
	if "" == s {
		return s
	}

	if 0 == maskChar {
		panic("maskChar is empty")
	}

	sArr := []rune(s)

	len := len(sArr)
	if start < 0 {
		start = 0
	}
	if start > len {
		return s
	}

	if end < 0 {
		panic("end is out of range")
	}

	if end > len {
		end = len
	}

	for i := 0; i < len; i++ {
		if i >= start && i < end {
			sArr[i] = maskChar
		}

	}

	return string(sArr)
}

func NewMaskEncoder(binding *jsoniter.Binding, tagValue string) *MaskEncoder {
	return &MaskEncoder{binding, tagValue}
}

type UpdateStructMaskFieldDescriptorExtension struct {
	jsoniter.DummyExtension
}

func (extension *UpdateStructMaskFieldDescriptorExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
	// 获取结构体标签注册解析
	for _, binding := range structDescriptor.Fields {
		tagValue := binding.Field.Tag().Get(tagx.MaskTagName)
		if "" == tagValue {
			continue
		}
		binding.Encoder = NewMaskEncoder(binding, tagValue)
	}

}
